package org.zjx.data.route;

import lombok.Data;
import org.zjx.command.entity.Route;
import org.zjx.command.entity.RouteQueryPojo;
import org.zjx.command.entity.screen.Address;
import org.zjx.data.route.algorithm.DijkstraPathFinding;
import org.zjx.data.route.algorithm.PathFindingStrategy;

import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 核心路由管理类
 * 职责：
 * 1. 整合静态路由和玩家动态路由
 * 2. 管理路径查找流程
 * 3. 提供高级查询接口
 */
@Data
public class RouteManager {
    private static RouteManager instance;

    public static synchronized RouteManager getInstance() {
        if (instance == null) {
            instance = new RouteManager();
        }
        return instance;
    }

    private final PathFindingStrategy pathFinder;
    private final TeleportFactory routeFactory;
    private final RouteGraphLoader loader;

    public RouteManager() {
        this(new DijkstraPathFinding(), new TeleportFactoryImpl());
    }

    public RouteManager(PathFindingStrategy pathFinder,
                        TeleportFactory routeFactory) {
        this.pathFinder = Objects.requireNonNull(pathFinder);
        this.routeFactory = Objects.requireNonNull(routeFactory);

        loader = new RouteGraphLoader(routeFactory);

    }

    /**
     * 查找完整路径（自动处理动态路由）
     *
     * @param routeQueryPojo 玩家数据（包含起点/终点/道具等）
     * @return 最优路径，null表示不可达
     */
    public List<Route> findPath(RouteQueryPojo routeQueryPojo) {
        RouteGraph graph = buildCompleteGraph(routeQueryPojo);
        Address startAddress = routeQueryPojo.getStart();
        Address endAddress = routeQueryPojo.getEnd();
        return pathFinder.findPath(graph, startAddress, endAddress);
    }

    /**
     * 查找满足时间限制的路径
     *
     * @param routeQueryPojo 玩家数据
     * @param maxTimeSeconds 最大允许耗时（秒）
     * @return 符合条件的路径
     */
    public List<Route> findPathWithinTime(RouteQueryPojo routeQueryPojo, int maxTimeSeconds) {
        RouteGraph graph = buildCompleteGraph(routeQueryPojo);

        Address startAddress = routeQueryPojo.getStart();
        Address endAddress = routeQueryPojo.getEnd();
        return pathFinder.findPathWithinTime(
                graph, startAddress, endAddress, maxTimeSeconds);
    }

    /**
     * 构建完整路由图（静态+动态）
     */
    private RouteGraph buildCompleteGraph(RouteQueryPojo routeQueryPojo) {
        RouteGraph graph = new RouteGraph(buildGraph(routeQueryPojo));
        Address startAddress = routeQueryPojo.getStart();
        Address endAddress = routeQueryPojo.getEnd();

        // 新增：同场景时直接连接起点和终点
        if (startAddress.getCity().equals(endAddress.getCity())) {
            if (!hasRouteBetween(graph, startAddress, endAddress)) {
                graph.addRoute(routeFactory.createRunningRoute(startAddress, endAddress));
            }
        } else {
            // 跨场景时连接起点/终点到传送点
            connectSpecialLocations(graph, startAddress, false);
            connectSpecialLocations(graph, endAddress, true);
        }
        return graph;
    }

    private RouteGraph buildGraph(RouteQueryPojo routeQueryPojo) {
        RouteGraph graph = new RouteGraph(loader.loadStaticGraph());

        // 添加玩家动态路由
        List<Route> dynamicRoutes = routeFactory.createPlayerRoutes(routeQueryPojo);
        graph.addAllRoutes(dynamicRoutes);

        // 确保所有动态路由的落地点有连接
        for (Route route : dynamicRoutes) {
            connectSpecialLocations(graph, route.getEnd(), false);
        }

        return graph;
    }

    /**
     * 连接特殊位置（起点/终点）的同场景路由
     */
    public void connectSpecialLocations(RouteGraph graph, Address location, boolean reverse) {

        // 1. 收集所有传送点的起点（本场景的传送起点）
        Set<Address> transferStartPoints = graph.getAllLocations().stream()
                .filter(loc -> graph.getRoutesFrom(loc).stream().anyMatch(route -> route.getType().isTransfer()))
                .filter(loc -> loc.getCity().equals(location.getCity()))
                .collect(Collectors.toSet());

        // 2. 收集所有传送点的终点（其他场景传送过来的落脚点）
        Set<Address> transferEndPoints = graph.getAdjacencyMap().values().stream()
                .flatMap(List::stream)
                .filter(route -> route.getType().isTransfer() && route.getEnd().getCity().equals(location.getCity()))
                .map(Route::getEnd)
                .collect(Collectors.toSet());

        if (!reverse) {
            for (Address startLocation : transferStartPoints) {
                if (hasRouteBetween(graph, location, startLocation)) continue;
                graph.addRoute(routeFactory.createRunningRoute(location, startLocation));
            }
        } else {
            for (Address endLocation : transferEndPoints) {
                if (hasRouteBetween(graph, endLocation, location)) continue;
                graph.addRoute(routeFactory.createRunningRoute(endLocation, location));
            }
        }
    }

    /**
     * 检查两个位置之间是否已有路由
     */
    private boolean hasRouteBetween(RouteGraph graph, Address from, Address to) {
        return graph.getRoutesFrom(from).stream()
                .anyMatch(route -> route.getEnd().equals(to));
    }

    /**
     * 计算路径总耗时
     */
    public static int calculateTotalTime(List<Route> path) {
        return PathFindingStrategy.getTotalTime(path);
    }
}